/*
 * @Author: xiaozhuang-c-language 3535851673@qq.com
 * @Date: 2025-05-01 20:11:55
 * @LastEditors: xiaozhuang-c-language 3535851673@qq.com
 * @LastEditTime: 2025-05-02 09:36:03
 * @FilePath: /zhuang/msgQueue/ChainofResponsibility.hpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */

#include<ctime>
#include<iostream>
#include<fstream>
#include<string>
#include <filesystem>
#include <sys/wait.h>
#include<memory>
#include <sys/types.h>
#include <sstream>
#include <unistd.h>
using namespace std;

string defaultfilepath = "./tmp/";
string defaultfilename = "test.log";


//责任链的基类
class HandlerText
{
public:
      virtual void Excute(const string& text) = 0;
      virtual ~HandlerText()
      {}
      void SetNext(shared_ptr<HandlerText> next)
      {
          _next = next;
      }
      void Enable()
      {
         _enable = true;
      }

      void Disable()
      {
         _enable  = false;
      }

protected: 
      std::shared_ptr<HandlerText> _next;   //下一责任链节点
      bool _enable;
};

//对文本进行格式化处理
class HandlerTextFormat : public HandlerText
{
    public:
        HandlerTextFormat(){}
        void Excute(const string& text) override
        {
            string format_ret = text + "\n";
            if(_enable)
            {
                //开关开启，对文本进行格式化处理
                std::stringstream ss; //时间
                time_t t = time(nullptr);
                struct tm* timeinfo = localtime(&t);
                ss << std::put_time(timeinfo, "%Y-%m-%d %H:%M:%S") << "-" << getpid() << "-" << text << "\n";
                format_ret = ss.str();
                cout << "step1 : 对文本进行格式化处理" << endl;
            }
            if(_next)
                _next->Excute(format_ret); //将处理结果表现在在text内部,传给下一个节点
            else 
              cout << "到达责任链处理结尾,完成责任链处理.." << endl;
        }
  
};

//对文本进行文件保存
class HandlerTextSaveFile : public HandlerText 
{
    public:
        HandlerTextSaveFile(const string& filepath = defaultfilepath,
                            const string& filename = defaultfilename)
        :_filepath(filepath),
         _filename(filename)
        {
            //形成默认的目录名
            if(std::filesystem::exists(_filepath))
               return;
            try
            {
                std::filesystem::create_directories(_filepath);
            }
            catch(std::filesystem::filesystem_error const& e)
            {
                     cerr << e.what() << "\n";
            }
        }

        void Excute(const string& text) override
        {
            if(_enable)
            {
                //开关开启，对文本进行文件保存
                string file = _filepath + _filename;
                std::ofstream ofs(file,std::ios::app);//注意是app
                if(!ofs.is_open()) //判断是否成功打开
                {
                    cerr << "open file error" << endl;
                    return;
                }
                ofs << text;
                cout << "step2 : 对文本进行文件保存.." << endl;
                ofs.close();
            }
            if(_next)
                _next->Excute(text); //将处理结果表现在在text内部,传给下一个节点
            else 
              cout << "到达责任链处理结尾,完成责任链处理.." << endl;
        }
    private:
       string _filepath;
       string _filename;    
};

const int defaultmaxline = 5;

//对文件内容长度进行检查，如果长度过长，对文件内容进行打包备份
class HandlerTextBackup : public HandlerText
{
    public: 
    HandlerTextBackup(const string& filepath = defaultfilepath,
        const string& filename = defaultfilename,int maxline = defaultmaxline)
        :_filepath(filepath),
        _filename(filename),
        _maxline(maxline)
        {}

      
      void Excute(const string& text) override 
      {
        if(_enable)
        {
            //开关开启，对文本进行检查，超出范围则切片打包备份
            string file = _filepath + _filename;
            if(IsOutRange(file))
            {
                cout << "step3 : 对文本进行检测是否超出行数范围" << endl;
                //打包备份
                Backup(file);
            }
        }
        if(_next)
            _next->Excute(text); //将处理结果表现在在text内部,传给下一个节点
        else 
          cout << "到达责任链处理结尾,完成责任链处理.." << endl;
      }
     private:
         bool IsOutRange(const string& file)
         {
             std::ifstream ifs(file);
             if(!ifs.is_open())
             {
                cerr << "open file error" << endl;
                return false;
             }
             int lines = 0;
             string line;
             while(getline(ifs,line))
                lines++;
            ifs.close();
            return lines > _maxline;
         }

         void Backup(const string& file)
         {
             //231312>时间戳动态命名
             string suffix = to_string(time(nullptr));
             //"./tmp/text.txtx" -> "./tmp/test.txt.213131" 带路径的也可以给父进程用
             string backupfile = file + "." + suffix;
             //只需要文件名 test.txt.231231
             string src_file = _filename + "." + suffix;
             //test.txt.1231231.tgz
             string dest_file = _filename+"."+suffix+".tgz";
             //创建子进程工作
             pid_t id = fork();
             if(id == 0)
             {
                //1.先对文件重命名 Linux原子
                std::filesystem::rename(file,backupfile);
                //2.让子进程进行数据备份
                //3.对备份文件进行打包成.tgz
                //3.1更改工作路径
                std::filesystem::current_path(_filepath);
                //3.2调用exec tar打包
                cout << "step4: 对文本进行切片打包备份..." << endl;
                execlp("tar","tar","-czf",dest_file.c_str(),src_file.c_str(),nullptr);
                exit(1);
             }
             //parent:删除备份文件
             int status = 0;
             pid_t rid = waitpid(id,&status,0);
             if(rid > 0)
             {
                if(WIFEXITED(status)&& WEXITSTATUS(status) == 0) //子进程成功才能删除备份文件
                {
                    //打包成功 删除备份文件
                    cout << "step5: 删除备份文件.. " << backupfile << endl;
                    std::filesystem::remove(backupfile); //需要带路径
                }
             }
         }

     private:
        string _filepath;
        string _filename;
        int _maxline; 
};

//责任链的入口函数

class HandlerTextEntry
{
public:
    HandlerTextEntry()
   {
       //1.构造责任链节点
      _format = std::make_shared<HandlerTextFormat>();
      _save = std::make_shared<HandlerTextSaveFile>();
      _backup = std::make_shared<HandlerTextBackup>();
       //2.设置关系
      _format->SetNext(_save);
      _save->SetNext(_backup);
      _backup->SetNext(nullptr);
   }

   void EnableHandler(bool format,bool save,bool backup)
   {
        format ? _format->Enable() : _format->Disable();
        save ? _save->Enable() : _save->Disable();
        backup ? _backup->Enable() : _backup->Disable();
   }

   ~HandlerTextEntry(){}

   //给上层调用的接口
   void Run(const string& text)
   {
      _format->Excute(text);
   }

private:
   std::shared_ptr<HandlerText> _format;
   std::shared_ptr<HandlerText> _save;
   std::shared_ptr<HandlerText> _backup;
};